package com.xiaomaoguai.fcp.pre.kepler.router.handler.handlers;

import com.xiaomaoguai.fcp.pre.kepler.router.buf.Buf;
import com.xiaomaoguai.fcp.pre.kepler.router.exception.RemoteException;
import com.xiaomaoguai.fcp.pre.kepler.router.exception.RouterException;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.client.okhttp.HttpClient;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.client.okhttp.HttpResponse;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.constants.HttpConstants;
import com.xiaomaoguai.fcp.pre.kepler.router.rpc.httpconverter.HessianSerializer;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.HandlerInfo;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.RouterInfo;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.api.Handler;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.api.HandlerContext;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.enums.CallBack;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.util.List;

@Component
public class RPCHandler implements Handler<Buf> {

	private final static Logger log = LoggerFactory.getLogger(RPCHandler.class);
	private final static HessianSerializer hessianSerializer = new HessianSerializer();
	private HandlerInfo remoteHandlerInfo;

	@Override
	public void beforeHandle(HandlerContext<Buf> hc) {
		Buf buf = hc.getBuf();
		List<RouterInfo> remoteInfos = buf.getRemoteInfos();
		StringBuilder sb = new StringBuilder();
		for (RouterInfo routerInfo : remoteInfos) {
			sb.append(routerInfo.getName()).append(",");
		}
		log.info("远程调用【{}】【{}】:{}", hc.getRouterInfo().appName(), hc.getRouterInfo().getUrl(), sb.toString());
	}

	@Override
	public void exceptionCaught(RouterException cause) {
		HandlerContext<?> handlerContext = cause.getHandlerContext();
		RouterInfo routerInfo = handlerContext.getRouterInfo();
		Buf buf = handlerContext.getBuf();
		buf.setException(null);
		log.info("bufId【{}】远程调用【{}】的【{}】返回异常:{}", buf.getId(), routerInfo.getHandlerInfo().getApplication(),
				buf.getExceptionHandlerName(), ExceptionUtils.getRootCauseMessage(cause));

	}

	@Override
	public void handle(HandlerContext<Buf> hc) {
		String url = hc.getUrl();
		Buf buf = hc.getBuf();
		buf.setRpcBuf(Boolean.TRUE);
		if (StringUtils.isBlank(url)) {
			throw new RouterException("rpc url is blank");
		}
		Buf newBuf = null;
		HttpResponse resp = HttpClient.post(url)
				 .contentType( HessianSerializer.CONTENT_TYPE)
//				 .send(kryoSerializer.writeObject(buf));
				 .send(hessianSerializer.writeObject(buf));
		if (resp.code() != HttpStatus.OK.value()
				|| !HessianSerializer.CONTENT_TYPE.equalsIgnoreCase(resp.header(HttpConstants.HEADER_CONTENT_TYPE))) {
			throw new RemoteException(resp.message());
		}
		byte[] bytes = resp.asByteData();
//		newBuf = Buf.class.cast(kryoSerializer.readObject(bytes));
		newBuf = Buf.class.cast(hessianSerializer.readObject(bytes));
		if (newBuf == null) {
			throw new RemoteException("调用无返回buf");
		} else if (newBuf.getException() != null) {
			newBuf.setRpcBuf(Boolean.FALSE);
			hc.setNewBuf(newBuf);
			throw new RemoteException(newBuf.getException());
		} else if (newBuf.getCallBack() != CallBack.WAIT && MapUtils.isEmpty(newBuf.getContext())) {
			newBuf.setRpcBuf(Boolean.FALSE);
			throw new RemoteException("调用返回无具体参数");
		} else {
			newBuf.setRpcBuf(Boolean.FALSE);
			hc.setNewBuf(newBuf);
		}
	}

	@Override
	public void genInnerParam(HandlerContext<Buf> hc) {

	}

	@Override
	public void handleCompleted(HandlerContext<Buf> hc) {
		RouterInfo routerInfo = hc.getRouterInfo();
		log.info("bufId【{}】 order【{}】 handlerName【{}】 and subsequent rpchandler completed",hc.getBuf().getId(), routerInfo.getOrder(),
				routerInfo.getName());

	}

	@Override
	public HandlerInfo getHandlerInfo() {
		return remoteHandlerInfo;
	}

	@Override
	public void setHandlerInfo(HandlerInfo handlerInfo) {
		this.remoteHandlerInfo = handlerInfo;
	}

	@Override
	public boolean isB2O() {
		return Boolean.FALSE;
	}

	@Override
	public String toString() {
		return remoteHandlerInfo == null ? "" : remoteHandlerInfo.toString();
	}

}
